package stcpscheculer;


import java.util.ArrayList;
import java.util.HashSet;
import java.util.List;
import java.util.Random;
import java.util.Set;

public class Population {

    int size;
    public int Buses;
    public int Drivers;
    public int TimeSlot; // in hours
    public int chromosomeLength;
    Chromosome[] Population;
    Chromosome bestSolution;
    float[] Psel; // probabilities of being selected
    float FA; // sum of all fa of the population

    /**
     *
     * @param int size
     * @param int buses
     * @param int drivers
     * @param int timeseg
     */
    public Population() {
        this.size = Configuration.getPopulationSize();
	this.Buses = Configuration.getBuses();
	this.Drivers = Configuration.getDrivers();
	this.TimeSlot = Configuration.getTimeSlot();
        this.chromosomeLength = Configuration.getChromosomeLength();
        FA = 0;
        Psel = new float[size];
        Population = new Chromosome[size];
        bestSolution = new Chromosome();
    }

    public Population getPopulation() {
        return this;
    }

    public Chromosome[] getChromosomes() {
        return Population;
    }

    /**
     * Evaluate population by running evaluation function for each individual
     *
     */
    public void evaluatePopulation() {
        for(Chromosome chr: Population){
            FA += chr.fa();
        }
    }

    /**
     * Calculates for each chromosome probability to be selected 
     * for the production of next generation
     * 
     */
    public void calcPsel() {
        for(int i=0; i<size; i++){
            Psel[i] = Population[i].getAdaptation()/FA;
        }
    }
    
    /**
     * Runs roulete to select chromosomes that will be used 
     * to produce a new generation
     * 
     * @return int[] - an array of selected chromosomes ids 
     */
    public int[] selectionRoulete(){
        int[] selected;
        selected = new int[size - 3];
        float[] Ps;
        Ps = new float[size];
        Ps[0]= Psel[0];
        for(int i=1;i<size;i++){
            Ps[i] = Ps[i-1] + Psel[i];
        }
        Random generator = new Random();
        for(int i=0;i<size-3;i++){
            float x = generator.nextInt(1000)/1000;
            for(int j=0;j<size;j++){
                if(x<=Ps[j]){
                    selected[i] = j;
                    break;
                }
            }
        }
        return selected;
    } 

    /**
     * Runs a roulet to choose chromosomes that will be crossed
     * 
     * @return int[] - an array of chromosomes' ids to be crossed
     */
    public int[] crossRoulete(){
        ArrayList<Integer> toCross = new ArrayList<Integer>();
        Random generator = new Random();
        int j=0;
        for(int i=0;i<size;i++){
            float x = generator.nextInt(10)/10;
            if(x<=Configuration.getPcross()){
                toCross.add(i);
                j++;
            }
        }
        int[] array = new int[toCross.size()];
        int i=0;
        for(Integer s: toCross){
            array[i++] = s;
        }
        return array;
    } 
    
    /**
     * Apply mutation to each chromosome in the population
     * 
     */
    public void mutate() {
        for(int i=0; i<size; i++){
            Population[i].mutate();
        }
    }
    
    /**
     * Creates initial population
     * 
     */
    public void initPopulation() {
        for (int i = 0; i < size; i++) {
            // create new chromosome
            Population[i] = new Chromosome();
            Population[i].init();
        }
    }
    
    /**
     * Compares solutions within a population
     * 
     * @return Chromosome that has the best value of fa()
     */
    public Chromosome bestSolution(){
        Chromosome chr = new Chromosome();
        float fa = 0;
        for(int i=0;i<size;i++){
            if(Population[i].getAdaptation()>fa){
                fa=Population[i].getAdaptation();
                chr=Population[i];
            }
        }
        bestSolution = chr;
        return bestSolution;
    }

    public Chromosome getBestSolution() {
        return bestSolution;
    }
    
}
